
(defvar my-ac-filename-cache nil
  "缓存文件名")

(defvar my-ac-filename-cache-dir nil
  "如果值为 nil 表示当前目录中的缓存")

(defvar my-ac-dir-sep "/"
  "目录分隔符")

(defun my-ac-filename-candidate ()
  ;; 得到 ac-prefix 的目录部分
  ;; 如果此目录的内容还没有在缓存中，那么
  ;; 调用 directory-files 赋值给 cache
  (let* ((dir (file-name-directory ac-prefix))
         (dir-real (or dir ".")))
    (when (file-directory-p dir-real)
      (when (or (not (equal dir my-ac-filename-cache-dir))
                (not my-ac-filename-cache))
        (setq my-ac-filename-cache-dir dir
              my-ac-filename-cache (directory-files dir-real nil))

        ;; 去掉 . 与 ..
        (setq my-ac-filename-cache
              (remove "." my-ac-filename-cache))
        (setq my-ac-filename-cache
              (remove ".." my-ac-filename-cache))

        ;; 加上目录
        (when dir
          (setq my-ac-filename-cache
                (mapcar (lambda (item)
                          (concat dir item))
                        my-ac-filename-cache)))

        ;; 为目录加上目录分隔符
        (setq my-ac-filename-cache
              (mapcar (lambda (item)
                        (if (file-directory-p item)
                            (concat item my-ac-dir-sep)
                          item))
                      my-ac-filename-cache)))
      my-ac-filename-cache)))

(defun my-ac-valid-filename ()
  (let* ((line-beg (line-beginning-position))
         (start (or (let ((point (re-search-backward "[\"<>' \t\r\n]" line-beg t)))
                      (if point (1+ point)))
                    line-beg)))
    start))

(defun my-ac-complete-dir ()
  (when (string= (char-to-string (preceding-char))
                 my-ac-dir-sep)
    (my-filename-complete)))

(defvar my-ac-source-filename
  '((init       . (setq my-ac-filename-cache nil
                        my-ac-filename-cache-dir nil))
    (candidates . my-ac-filename-candidate)
    (prefix     . my-ac-valid-filename)
    (action     . my-ac-complete-dir)
    (limit      . 0)))

(defun my-filename-complete ()
  (interactive)
  (let ((bak ac-sources))
    (unwind-protect
        (progn (setq ac-sources '(my-ac-source-filename))
               (auto-complete)
               (setq ac-sources bak))
      (setq ac-sources bak))))

(provide 'my-filename-complete)
